#ifndef __SAL_MUTEX_H__
#define __SAL_MUTEX_H__

/**
 * @file sal_mutex.h
 */

/**
 * @defgroup mutex Mutexes
 * @{
 */

#ifdef __cplusplus
extern "C"
{
#endif

/** Mutex Object */
typedef struct sal_mutex sal_mutex_t;

#define SAL_SEM_FOREVER     (-1)
/** Sem Object */
typedef struct sal_sem sal_sem_t;

#ifdef SAL_DEBUG_MUTEX

#define SAL_HOLD_LK_NUM_MAX 10
#define SAL_LOC_NAME_MAX 64
#define SAL_MUTEX_UPDATE_THRD 30

struct sal_task_mutex_info
{
    sal_mutex_t* req_lk;
    sal_mutex_t* hold_lk[SAL_HOLD_LK_NUM_MAX];
    char lk_req_location[SAL_LOC_NAME_MAX];
    char ulk_req_location[SAL_LOC_NAME_MAX];
    uint32 hold_lk_cnt;
    sal_time_t time;
    pid_t tid;
};
typedef struct sal_task_mutex_info sal_task_mutex_info_t;

struct sal_task_mutex
{
    sal_task_mutex_info_t* info[CTC_SAL_TASK_MAX_NUM];
    uint8 tid_num;
    uint8 init;
};
typedef struct sal_task_mutex sal_task_mutex_t;

extern sal_task_mutex_t g_task_mutex;
#endif
/**
 * Create a new mutex
 *
 * @param[out] pmutex
 *
 * @return
 */
sal_err_t ctc_sal_mutex_create(sal_mutex_t** pmutex);

/**
 * Destroy the mutex
 *
 * @param[in] mutex
 */
void ctc_sal_mutex_destroy(sal_mutex_t* mutex);

#ifdef SAL_DEBUG_MUTEX
/**
 * Lock the mutex
 *
 * @param[in] mutex
 */
void ctc_sal_mutex_lock(sal_mutex_t* mutex, const char *take_loc, int line);

/**
 * Unlock the mutex
 *
 * @param[in] mutex
 */
void ctc_sal_mutex_unlock(sal_mutex_t* mutex, const char *give_loc, int line);
#else
/**
 * Lock the mutex
 *
 * @param[in] mutex
 */
void ctc_sal_mutex_lock(sal_mutex_t* mutex);

/**
 * Unlock the mutex
 *
 * @param[in] mutex
 */
void ctc_sal_mutex_unlock(sal_mutex_t* mutex);
#endif
/**
 * Try to lock the mutex
 *
 * @param[in] mutex
 *
 * @return
 */
bool ctc_sal_mutex_try_lock(sal_mutex_t* mutex);

/**
 * Create a new sem
 *
 * @param[out] pp_sem
 *
 * @param[in] init count
 *
 * @return
 */
sal_err_t ctc_sal_sem_create(sal_sem_t** pp_sem, uint32 init_count);

/**
 * Destroy the sem
 *
 * @param[in] p_sem
 *
 * @return
 */
sal_err_t ctc_sal_sem_destroy(sal_sem_t* p_sem);

/**
 * Task the sem
 *
 * @param[in] p_sem
 *
 * @param[in] usec
 *
 * @return
 */
sal_err_t ctc_sal_sem_take(sal_sem_t* p_sem, int32 msec);

/**
 * Give the sem
 *
 * @param[in] p_sem
 *
 * @return
 */
sal_err_t ctc_sal_sem_give(sal_sem_t* p_sem);


extern uint64
ctc_sal_intlog10(uint32 value);
extern uint64
ctc_sal_intlog2(uint32 value);
extern uint64
ctc_sal_intpow(uint64 a, uint32 exp);
extern uint32
ctc_sal_intround(uint32 base, uint32 factor);
extern uint64
ctc_sal_intsqrt(uint64 num);

#ifdef SAL_DEBUG_MUTEX
void ctc_sal_mutex_dump(pid_t tid);
sal_err_t ctc_sal_mutex_init(void);
void ctc_sal_mutex_deinit(void);

#endif

#ifdef __cplusplus
}
#endif

/**@}*/ /* End of @defgroup mutex */

#endif /* !__SAL_MUTEX_H__ */
